﻿using UnityEngine;
using System;
using System.Collections;
using UnityEditor;

namespace Hont.BlazingNodePackage
{
    public partial class BlazingNodeEditor_View
    {
        ParameterItemVO mSelectionParameterItemVO;
        ParameterItemVO mDragParameterItemVO;
        ParameterVO mParameterVO;
        int mToolbagIndex;
        int mToolbagParamIndex;
        int mTempTypeSelectIndex;
        bool mIsDraggingFunctionItem;

        Vector2 mFunctionPanelScrollView;

        Rect mMouseDownLeftContentRect;
        bool mIsDraggingLeftContentState;

        Rect ToolbagRect
        {
            get
            {
                return new Rect(
                        ContentPanelOriginX + SMALL_SPACING
                        , ContentPanelOriginY + SMALL_SPACING
                        , LeftContentPanelWidth - SMALL_SPACING * 2
                        , ContentPanelHeight - SMALL_SPACING * 2);
            }
        }


        void InitFunctionPanel()
        {
            mParameterVO = new ParameterVO() { ParameterVOArray = new ParameterItemVO[0] };
        }

        public void Update_ParameterVO(ParameterVO parameterVO)
        {
            mParameterVO = parameterVO;
        }

        void RefreshToolbag()
        {
            mToolbagIndex = GUI.Toolbar(new Rect(ToolbagRect.x, ToolbagRect.y, ToolbagRect.width, 20)
                 , mToolbagIndex
                 , new GUIContent[]
                    {
                        new GUIContent("Parameters"),
                        new GUIContent("Attributes"),
                    });

            var originY = ToolbagRect.y + 20 + MID_SPACING;
            var rect = new Rect(ToolbagRect.x, originY, ToolbagRect.width, ToolbagRect.yMax - originY);

            switch (mToolbagIndex)
            {
                case 0://Parameters List.
                    {
                        RefreshParametersList(rect);
                    }
                    break;

                case 1://Attributes.
                    {
                        RefreshAttributes(rect);
                    }
                    break;
            }

            RefreshDraggingFunctionItem();

            RefreshDragFunctionSlider();
        }

        void RefreshParametersList(Rect rect)
        {
            var hasInParamArea = false;

            var lastHeight = 0f;
            var paramHeight = 20f + SMALL_SPACING * 2f;

            var viewRect = new Rect(0, 0, rect.width - MID_SPACING, mParameterVO.ParameterVOArray.Length * (MID_SPACING + paramHeight) + 50);

            mFunctionPanelScrollView = GUI.BeginScrollView(rect, mFunctionPanelScrollView, viewRect);

            var relativeMousePosition = (mMousePosition - rect.min) + mFunctionPanelScrollView;

            for (int i = 0; i < mParameterVO.ParameterVOArray.Length; i++)
            {
                var item = mParameterVO.ParameterVOArray[i];

                var paramBoundRect = new Rect(0, lastHeight, rect.width, paramHeight);

                lastHeight = lastHeight + paramHeight + MID_SPACING;

                var oldColor = GUI.color;

                GUI.color = mDragParameterItemVO == item
                    && !paramBoundRect.Contains(relativeMousePosition)
                    && mParameterVO.ParameterVOArray.Length > 1
                        ? Color.Lerp(GUI.color, Color.black, 0.4f)
                        : GUI.color;

                GUI.Box(paramBoundRect, "", GUI.skin.button);

                var nameAreaRect = paramBoundRect;
                nameAreaRect.width *= 0.5f;
                nameAreaRect.y += SMALL_SPACING;
                GUI.Label(nameAreaRect, item.Name);

                var valueRect = nameAreaRect;
                valueRect.x += valueRect.width;
                item.OnDrawFieldGUICB(valueRect);

                if (mSelectionParameterItemVO == item)
                {
                    var detailRect = new Rect(paramBoundRect.x, paramBoundRect.y + 32, paramBoundRect.width, 80);
                    GUI.Box(detailRect, "");

                    var halfWidth = detailRect.width * 0.5f;
                    EditorGUI.LabelField(new Rect(detailRect.x, detailRect.y + 3f, halfWidth, 25), "Name");
                    var changedName = EditorGUI.TextField(new Rect(detailRect.x + halfWidth, detailRect.y + SMALL_SPACING, halfWidth, 17), item.Name);

                    if (item.Name != changedName)
                    {
                        mParameterVO.OnNameChangeCB(item, changedName);

                        mIsMouseDown = false;
                        mDragParameterItemVO = null;
                    }

                    detailRect.y += 20f;
                    EditorGUI.LabelField(new Rect(detailRect.x, detailRect.y + 3f, halfWidth, 25), "Value");
                    detailRect.y += 20f;
                    item.OnDrawFieldGUICB(new Rect(detailRect.x, detailRect.y, detailRect.width, 20));

                    EditorGUI.LabelField(new Rect(detailRect.x, detailRect.y + 20, halfWidth, 25), "Type");

                    if (mTempTypeSelectIndex == -1)
                    {
                        mTempTypeSelectIndex = Array.IndexOf(mParameterVO.ParameterTypesArray, item.Type);
                    }

                    var oldFocus = GUI.GetNameOfFocusedControl();

                    GUI.SetNextControlName("popup");
                    var changedIndex = EditorGUI.Popup(new Rect(detailRect.x + halfWidth, detailRect.y + 20, halfWidth, 25), mTempTypeSelectIndex
                        , mParameterVO.ParameterTypesArray);

                    var newFocus = GUI.GetNameOfFocusedControl();

                    if (newFocus != oldFocus)
                    {
                        mIsMouseDown = false;
                        mDragParameterItemVO = null;

                        GUI.FocusControl("");
                    }

                    if (changedIndex != mTempTypeSelectIndex)
                    {
                        mParameterVO.OnTypeChangeCB(item, mParameterVO.ParameterTypesArray[changedIndex]);
                        mTempTypeSelectIndex = -1;
                    }

                    if (detailRect.Contains(relativeMousePosition))
                        hasInParamArea = true;

                    lastHeight += 83;
                }

                GUI.color = oldColor;

                if (paramBoundRect.Contains(relativeMousePosition))
                    hasInParamArea = true;

                ProcessParametersItemInput(relativeMousePosition, nameAreaRect, paramBoundRect, item, i);
            }

            GUI.EndScrollView();

            if (mIsMouseUp)
                mDragParameterItemVO = null;

            if (!hasInParamArea && rect.Contains(mMousePosition) && mIsMouseDoubleClicke && mLastMouseButton == 0)
            {
                if (mParameterVO.OnCreateParameterCB != null)
                    mParameterVO.OnCreateParameterCB();
            }

            if (mSelectionParameterItemVO == null)
                mTempTypeSelectIndex = -1;
        }

        void ProcessParametersItemInput(Vector2 relativeMousePosition, Rect nameAreaRect, Rect paramBoundRect, ParameterItemVO item, int index)
        {
            if (mLastMouseButton == 2) return;

            if (nameAreaRect.Contains(relativeMousePosition) && mIsMouseUpOnce && mLastMouseButton == 0)
            {
                if (item.OnClickedCB != null)
                    item.OnClickedCB(item);

                if (mSelectionParameterItemVO == item) mSelectionParameterItemVO = null;
                else mSelectionParameterItemVO = item;

                GUI.FocusControl("");
            }

            //----Right Click
            if (paramBoundRect.Contains(relativeMousePosition) && mLastMouseButton == 1)
            {
                var genericMenu = new GenericMenu();
                genericMenu.AddItem(new GUIContent("Delete"), false, () =>
                {
                    mParameterVO.OnDeleteCB(item);
                    mIsMouseDown = false;
                    mDragParameterItemVO = null;
                });

                genericMenu.ShowAsContext();

                return;
            }
            //---------------------

            //----Drag or Drop
            if (nameAreaRect.Contains(relativeMousePosition) && mIsMouseDown && mDragParameterItemVO == null)
            {
                mDragParameterItemVO = item;
                mIsDraggingFunctionItem = true;
            }

            var dragTipRect = new Rect(paramBoundRect.x, paramBoundRect.y, paramBoundRect.width, 10f);

            if (mIsMouseDown
                && mDragParameterItemVO != item
                && dragTipRect.Contains(relativeMousePosition))
            {
                if (mDragParameterItemVO != null)
                {
                    dragTipRect.height = 3f;
                    GUI.Box(dragTipRect, "");
                }
            }

            if (mIsMouseUpOnce
                && mDragParameterItemVO != item
                && mDragParameterItemVO != null
                && dragTipRect.Contains(relativeMousePosition))
            {
                if (mParameterVO.OnSwapParameterItemCB != null)
                    mParameterVO.OnSwapParameterItemCB(mDragParameterItemVO, index);

                mDragParameterItemVO = null;
                mIsDraggingFunctionItem = false;

                return;
            }

            if (index == mParameterVO.ParameterVOArray.Length - 1)
            {
                dragTipRect = new Rect(paramBoundRect.x, paramBoundRect.y, paramBoundRect.width, 10f);
                dragTipRect.y = paramBoundRect.yMax;

                if (mIsMouseDown
                    && mDragParameterItemVO != item
                    && dragTipRect.Contains(relativeMousePosition))
                {
                    if (mDragParameterItemVO != null)
                    {
                        dragTipRect.height = 3f;
                        GUI.Box(dragTipRect, "");
                    }
                }

                if (mIsMouseUpOnce
                    && mDragParameterItemVO != item
                    && mDragParameterItemVO != null
                    && dragTipRect.Contains(relativeMousePosition))//Drop reorder.
                {
                    if (mParameterVO.OnSwapParameterItemCB != null)
                        mParameterVO.OnSwapParameterItemCB(mDragParameterItemVO, index + 1);

                    mDragParameterItemVO = null;
                    mIsDraggingFunctionItem = false;

                    return;
                }

                if (mIsMouseUpOnce
                    && mDragParameterItemVO != null
                    && NodeGraphRect.Contains(mMousePosition))//Drop to node group.
                {
                    if (mParameterVO.OnDropToNodeGraphCB != null)
                        mParameterVO.OnDropToNodeGraphCB(mDragParameterItemVO, (mMousePosition - NodeGraphRect.min) + mNodeGraphScrollPosition);

                    mDragParameterItemVO = null;
                    mIsDraggingFunctionItem = false;

                    return;
                }

                if (mIsMouseUpOnce)
                {
                    mDragParameterItemVO = null;
                    mIsDraggingFunctionItem = false;
                }
            }
            //---------------------
        }

        void RefreshAttributes(Rect rect)
        {
            GUILayout.BeginArea(rect);

            if (mSelectionNodeList.Count == 1)
            {
                var item = mSelectionNodeList[0];
                if (item.OnDrawAttributesGUICB != null)
                    item.OnDrawAttributesGUICB(item);
            }
            else
            {
                if (rect.Contains(mMousePosition))
                    GUI.FocusControl("");
            }

            GUILayout.EndArea();
        }

        void RefreshDraggingFunctionItem()
        {
            if (!mIsDraggingFunctionItem) return;
            if (mDragParameterItemVO == null) return;
            if (!NodeGraphRect.Contains(mMousePosition)) return;

            var paramHeight = 20f + SMALL_SPACING * 2f;
            var rect = new Rect(0, 0, ToolbagRect.width, paramHeight);
            rect.center = mMousePosition + new Vector2(14, 4);

            GUI.Box(rect, "", GUI.skin.button);

            var nameAreaRect = rect;
            nameAreaRect.width *= 0.5f;
            nameAreaRect.y += SMALL_SPACING;
            GUI.Label(nameAreaRect, mDragParameterItemVO.Name);

            var valueRect = nameAreaRect;
            valueRect.x += valueRect.width;
            mDragParameterItemVO.OnDrawFieldGUICB(valueRect);
        }

        void RefreshDragFunctionSlider()
        {
            var rect = new Rect(LeftContentPanelWidth + 3, ToolbagRect.y, 8, ContentPanelHeight);

            EditorGUIUtility.AddCursorRect(rect, MouseCursor.ResizeHorizontal);

            if (mIsMouseUpOnce)
            {
                mIsDraggingLeftContentState = false;
                mMouseDownLeftContentRect = new Rect();
                return;
            }

            if (mIsMouseDownOnce)
                mMouseDownLeftContentRect = rect;

            if (mIsMouseDown
                && rect.Contains(mMousePosition)
                && !mIsDraggingFunctionItem
                && mMouseDownLeftContentRect.Contains(mMouseDownPosition))
            {
                LeftContentPanelWidth = mMousePosition.x;

                mIsDraggingLeftContentState = true;
            }

            if (mIsDraggingLeftContentState)
            {
                LeftContentPanelWidth = mMousePosition.x - rect.size.x * 0.5f;
            }
        }
    }
}
